<template>
  <div class="UploadTableNew-container">
    <a-upload
      v-if="!disabled"
      v-bind="$attrs"
      name="file"
      :before-upload="beforeUpload"
      :show-upload-list="false"
      :multiple="multiple"
      @change="handleChanges"
    >
      <a-button
        v-if="useAdd"
        class="mb12"
        :loading="loadingState.isUpload"
        :disabled="disabled || loadingState.isUpload"
        type="primary"
      > 上传 </a-button>
    </a-upload>
    <a-button
      v-if="!disabled && useMultiDelete && useDelete"
      class="mb12 ml12"
      type="default"
      :disabled="!selectedRowKeys.length"
      @click="handleClickBatchDelete"
    > 删除 </a-button>
    <a-button
      v-if="useMultiExport"
      class="mb12 ml12"
      type="default"
      :disabled="!selectedRowKeys.length"
      @click="handleClickBatchExport"
    > 选中导出 </a-button>
    <slot name="head" />
    <s-table
      ref="table"
      :row-key="replaceKeyName"
      :columns="columns"
      :data="loadData"
      show-size-changer
      show-quick-jumper
      :show-pagination="needPage ? 'auto' : false"
      :use-cache="false"
      :row-selection="rowSelection"
      :loading="loadingState.isUpload"
    >
      <template
        slot="action"
        slot-scope="text, record"
      >
        <div class="pub-table-list-action">
          <span
            v-if="checkVisibleInDetail"
            @click="handleUpdate(record, 'export')"
          >
            <a v-if="useExport"
              :href="'/api/ycloud-file-center/oper/download?access_token=' + token + '&fileId=' + record.fileId"
              target="_parent"
            > 导出 </a>
            <span @click="$filePreview(record)" v-if="useLook">查看</span>
          </span>
          <span
            v-if="deleteVisible(record)"
            @click="handleUpdate(record, 'delete')"
          >删除</span>
        </div>
      </template>
    </s-table>
  </div>
</template>

<script>
import { deleteFile, downZip } from '@/api'
import { checkVisibleInDetail } from '@/utils/util'
import { STable } from '@/components' // 表格
import Vue from 'vue'
import { uploadFile } from '@/api'
import debounce from 'lodash/debounce'

const columns = [
  {
    title: '序号',
    dataIndex: 'serial',
    width: '10%',
    customRender() {
      return arguments[2] + 1
    }
  },
  {
    title: '附件名称',
    dataIndex: 'fileName'
  },
  {
    title: '附件格式',
    dataIndex: 'suffixName',
    width: '15%'
  },
  {
    title: '操作',
    key: 'action',
    width: '20%',
    scopedSlots: { customRender: 'action' }
  }
]
export default {
  name: 'UploadTableNew',
  components: {
    STable
  },
  props: {
    // 文件列表数据的key值
    replaceKeyName: {
      type: String,
      default: 'commonId'
    },
    // 上传文件的业务编码
    businessCode: {
      type: String,
      require: true,
      default: ''
    },
    // 文件列表请求接口，返回一个promise
    requestFn: {
      type: Function,
      require: true,
      default: null
    },
    // 处理操作的模式：'add'模式下，删除操作会调用文件删除接口，'edit'模式只会在表格中移除删除数据，不会调用接口
    mode: {
      type: String,
      default: 'add'
    },
    disabled: {
      type: Boolean,
      default: false
    },
    // 是否需要分页
    needPage: {
      type: Boolean,
      default: true
    },
    // 初始化文件列表
    initFileList: {
      type: Array,
      default() {
        return []
      }
    },
    // 是否使用批量删除
    useMultiDelete: {
      type: Boolean,
      default: false
    },
    // 是否选中导出
    useMultiExport: {
      type: Boolean,
      default: false
    },
    // 是否需要上传
    useAdd: {
      type: Boolean,
      default: true
    },
    // 是否需要删除
    useDelete: {
      type: Boolean,
      default: true
    },
    // 是否需要导出
    useExport: {
      type: Boolean,
      default: true
    },
     // 是否需要查看
    useLook: {
      type: Boolean,
      default: true
    },
    // 是否必须上传中文名字
    needChineseName: {
      type: Boolean,
      default: false
    },
    // 默认多选开启
    multiple: {
      type: Boolean,
      default: () => true
    },
    deleteFileFun: {
      type: [ Promise, Function ],
      default: null
    },
    // 可上传数量
    count: {
      type: [String, Number],
      default() {
        return 100
      }
    },
    // 创建人才能删除
    useDeleteCreator: {
      type: Boolean,
      default: false
    },
    // 创建时间
    useCreateTime: {
      type: Boolean,
      default: false
    },
    // 创建时间
    btnText: {
      type: String,
      default: "上传"
    },
  },
  data() {
    return {
      checkVisibleInDetail,
      token: '',
      deleteList: [], // 记录已删除的文件commonId列表
      fileList: [], // 记录新增的文件
      selectedRowKeys: [],
      loadingState: {
        isUpload: false
      },
      // 批量导出文件加载
      downLoading: false,
      // 一次最多上传
      num: 10,
      isEnd: false, //是否最后页展示,
      // 文件列表
      files: []
    }
  },
  watch: {
    initFileList: {
      immediate: true,
      deep: true,
      handler(newList) {
        if (newList) {
          this.fileList = newList || []
          this.refreshTable()
        }
      }
    }
  },
  computed: {
    rowSelection() {
      if ((this.disabled || !this.useMultiDelete) && !this.useMultiExport) {
        return null
      }
      return {
        selectedRowKeys: this.selectedRowKeys,
        onChange: this.handleSelectedChanged
      }
    },
    // 表头
    columns() {
      if(this.useCreateTime ){
        let list = this.$clone(columns)
        list.splice(
          3,
          0,
          {
            title: '上传人',
            dataIndex: 'createUser',
            width: 220
          },
          {
            title: '上传时间',
            dataIndex: 'createTime',
            width: 180
          }
        )
        return list
      }else{
        return columns
      }
    }
  },
  created() {
    this.initPage()
  },
  methods: {
    /**
     * 点击批量删除
     */
    handleClickBatchDelete() {
      this.$confirm({
        title: '删除',
        content: '确定删除选中附件吗？',
        onOk: async () => {
          this.deleteList = this.deleteList.concat(this.selectedRowKeys)
          this.selectedRowKeys = []
          this.$message.success('删除成功')
          this.refreshTable()
        }
      })
    },
    async handleClickBatchExport() {
      this.downLoading = true
      await downZip(
        {
          fileIds: this.selectedRowKeys,
          urlStr: location.origin
        },
        '深化设计策划书/盈亏分析表'
      )
      this.downLoading = false
    },
    /**
     * 选中数据变化
     * @param {Array} selectedRowKeys - 所有已选行的key
     * @param {Array} selectedRows - 所有已选行
     */
    handleSelectedChanged(selectedRowKeys, selectedRows) {
      this.selectedRowKeys = selectedRowKeys
    },
    initPage() {
      this.token = Vue.getAcloudProvider().getAccessToken()
    },
    /**
     * 返回变动的fileId数组，默认返回新增、删除的数组，但如果是不分页（needPage为true）的情况，则返回当前表格的所有文件的数组
     */
    getChangedFileIds() {
      if (!this.needPage) {
        return {
          allList: this.fileList
            .map((item) => item[this.replaceKeyName])
            .filter((id) => {
              return !this.deleteList.includes(id)
            })
        }
      }
      return {
        addIds: this.fileList.map((item) => item[this.replaceKeyName]).filter((item) => !!item),
        delIds: this.deleteList.filter((item) => !!item),
        loadList: this.loadList || [] // 接口所请求到的文件列表（编辑时，可通过该字段结合addIds字段，判断表格是否有数据：addIds和loadList都为空时，表格为空）
      }
    },
    /**
     * @description: 提示防抖
     * @param {void}
     * @return {function}
     */
    numMesgDebounce: debounce(function () {
      this.$message.error(`一次最多上传${this.num}个文件！`)
    }, 500),
    /**
     * @description: 附件名弹窗提示
     * @param {void}
     * @return {function}
     */
    nameDebounce: debounce(function () {
      this.$confirm({
        title: '提示',
        content: this.errorTips ? this.errorTips : '请规范附件名称，附件名称中需含有汉字',
        okType: 'danger'
      })
    }, 500),
    /**
     * @description: 500M提示
     * @param {void}
     * @return {function}
     */
    sizeDebounce: debounce(function () {
      this.$message.error('上传文件不可超出500M')
    }, 500),
    /**
     * @description: 接管文件上传
     * @param {object} info 文件对象
     * @return {void}
     */
    handleChanges(info) {
      let pass = true
      const { file } = info
      if (file.size / 1024 / 1024 > 500) {
        // 附件大小校验
        // 限制文件大小为500M
        this.sizeDebounce()
        pass = false
      }
      if (this.needChineseName) {
        // 附件名称需要汉字校验
        let re = new RegExp('[\u4E00-\\u9FFF]+', 'g')
        if (!re.test(file.name)) {
          this.nameDebounce()
          pass = false
        }
      }
      if (pass) {
        this.files.push(file)
        this.fileChange()
      }
    },
    /**
     * @description: 文件上传防抖
     * @param {function}
     * @return {void}
     */
    fileChange: debounce(function () {
      this.handleUploadFun()
    }, 500),
    /**
     * @description: 判断及操作上传文件队列
     * @return {void}
     */
    async handleUploadFun() {
      let pass = true
      if (pass && this.fileList.length + this.files.length > this.count) {
        pass = false
        this.$message.error(`最多上传${this.count}个文件！`)
        this.files = this.files.slice(0, this.count - this.fileList.length)
      }
      if (this.multiple) {
        if (pass && this.files.length > this.num) {
          this.$message.error(`一次最多上传${this.num}个文件！`)
          this.files = this.files.slice(0, this.num)
        }
      }
      this.loadingState.isUpload = true
      // 防止上传错误一直loading
      try {
        for (let i = 0; i < this.files.length; i++) {
          await this.uploadFun(this.files[i])
        }
      } catch (err) {
        console.log(err)
      } finally {
        this.files = []
        this.loadingState.isUpload = false
        // 上传完成回调
        this.$emit('uploaded')
      }
    },
    /**
     * @description: 上传函数拆分
     * @param {FormData} info
     * @return {void}
     */
    uploadFun(info) {
      return new Promise(async (resolve, reject) => {
        try {
          const formData = new FormData()
          formData.append('file', info)
          formData.append('businessCode', this.businessCode)
          const res = await uploadFile(formData)
          this.fileList.push(res.data)
          this.isEnd = true
          this.refreshTable()
          resolve()
        } catch (e) {
          console.error(e)
          reject()
        }
      })
    },
    /**
     * 拦截上传
     * @param {Object} info - 文件信息的对象
     */
    beforeUpload(info) {
      // const { size, name } = info
      // if (size / 1024 / 1024 > 500) {
      //   this.$message.warning('上传文件不可超出500M')
      //   return false
      // }
      // if (this.needChineseName) {
      //   let re = new RegExp('[\\u4E00-\\u9FFF]+', 'g')
      //   if (!re.test(name)) {
      //     this.$confirm({
      //       title: '提示',
      //       content: '请规范附件名称，附件名称中需含有汉字',
      //       okType: 'danger'
      //     })
      //     return false
      //   }
      // }
      return false
    },
    /**
     * 删除文件
     * @param {Object} data - 文件对象
     */
    deleteFile(data) {
      this.$confirm({
        title: '删除',
        content: '确定删除附件吗？',
        onOk: async () => {
          // 编辑的时候假删除，在提交成功之后，可调用本组件的batchDeleteFile方法将之前假删除的文件删除
          if (this.mode === 'edit') {
            this.deleteList.push(data[this.replaceKeyName])
            const targetIndex = this.fileList.findIndex((item) => item[this.replaceKeyName] === data[this.replaceKeyName])
            if (targetIndex > -1) {
              this.fileList.splice(targetIndex, 1)
            }
            this.$message.success('删除成功')
            this.refreshTable()
            return
          }
          console.log(this.mode)
          const fun = typeof deleteFileFun === 'function' ? deleteFileFun : deleteFile
          await fun([data[this.replaceKeyName]])
          this.$message.success('删除成功')
          this.deleteList.push(data[this.replaceKeyName])
          const targetIndex = this.fileList.findIndex((item) => item[this.replaceKeyName] === data[this.replaceKeyName])
          if (targetIndex > -1) {
            this.fileList.splice(targetIndex, 1)
          }
          this.refreshTable()
          // 删除完成回调
          this.$emit('deleted')
        }
      })
    },
    /**
     * 批量删除已记录在deleteList（删除数组）中的文件，通常在保存或提交成功后，调用该方法来删除对应的文件
     */
    batchDeleteFile() {
      if (!this.deleteList.length) return
      return deleteFile(this.deleteList)
    },
    /**
     * 操作数据
     * @param {Object} data 操作的数据值
     * @param {String} actionType 操作类型  'export' | 'delete'
     */
    handleUpdate(data, actionType) {
      const actionMap = {
        export: () => {},
        delete: this.deleteFile
      }
      actionMap[actionType] && actionMap[actionType](data)
    },
    refreshTable() {
      this.$refs.table && this.$refs.table.refresh(false)
    },
    loadData(params) {
      //如果是点击上传文件且成功则记录到末尾页
      if (this.isEnd) {
        params.pageNo = this.fileList.length % params.pageSize > 0 ? this.fileList.length / params.pageSize + 1 : this.fileList.length / params.pageSize
        setTimeout(() => {
          this.isEnd = false
        }, 3000)
      }
      // 不需要分页时，直接对fileList进行操作
      if (!this.needPage) {
        return Promise.resolve({
          data: this.fileList.filter((item) => {
            return !this.deleteList.includes(item[this.replaceKeyName])
          })
        })
      }
      // 新增模式下，采用前端分页
      if (this.mode === 'add') {
        const dataList = this.fileList.filter((item) => {
          return !this.deleteList.includes(item[this.replaceKeyName])
        })
        return Promise.resolve({
          currentPage: params.pageNo,
          data: dataList,
          totalSize: dataList.length
        })
      }

      // 编辑模式下，通过接口获取当前页数据，再组合用户新增或删除的数据，前端分页之后返回
      return this.requestFn(params).then((res) => {
        const dataList = (res.data || [])
          .map((item) => {
            item = item.fileInfoVO || item
            return item
          })
          .concat(this.fileList)
          .filter((item) => {
            return !this.deleteList.includes(item[this.replaceKeyName])
          })
        const originRemoveList = this.deleteList.filter((key) => {
          return this.fileList.findIndex((fileItem) => fileItem[this.replaceKeyName] === key) < 0
        })
        this.loadList = dataList
        return {
          data: dataList,
          currentPage: params.pageNo,
          totalSize: this.fileList.length + res.totalSize - originRemoveList.length
        }
      })
    },
    /**
     * @description: 是否显示删除按钮(开启时匹配当前文件的创建人是否是当前登录人,因为开发环境createPerson这个字段没有值会导致匹配不上所以不会显示删除按钮，所以取createUserId这个字段是后端详情接口返回，所以每次上传之后需要掉查询接口回显)
     * @param {object} record 行数据
     * @return {void}
     */    
    deleteVisible(record){
      return this.useDeleteCreator ? (record.createUserId === this.$store.state.user.userInfo.id) && !this.disabled && this.useDelete && record.useDelete !== false : !this.disabled && this.useDelete && record.useDelete !== false
    }
  }
}
</script>

<style>
</style>
